using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Gko.Utils;

namespace Gko.Video.Extensions
{
	[Serializable]
	public class ColorDepth : IEquatable<ColorDepth>
	{
		public static readonly int MinBpp = 1;
		public static readonly int MaxBpp = 96;
		private readonly decimal colors;
		private readonly int bpp;

		public ColorDepth(decimal colors)
		{
			this.colors = colors;
			this.bpp = (int)Math.Log((double)colors, 2);
		}

		public override string ToString()
		{
			return "{0}bpp ({1})".Format(this.bpp, this.colors);
		}

		/// <exception cref="ArgumentOutOfRangeException"><c>bpp</c> is out of range (1..96).</exception>
		public ColorDepth(int bpp)
		{
			if (bpp > MaxBpp) {
				throw new ArgumentOutOfRangeException("bpp", bpp, "Must be less or equal to " + MaxBpp);
			}
			if (bpp < MinBpp) {
				throw new ArgumentOutOfRangeException("bpp", bpp, "Must be greater than 0");
			}
			this.bpp = bpp;
			this.colors = 1;
			for (var i = 0; i < bpp; i++) {
				this.colors = Decimal.Multiply(this.colors, 2M);
			}
		}

		public ColorDepth(decimal colors, int bpp)
		{
			this.colors = colors;
			this.bpp = bpp;
		}

		public int BitsPerPixel
		{
			get
			{
				return this.bpp;
			}
		}

		public decimal Colors
		{
			get
			{
				return this.colors;
			}
		}

		public bool Equals(ColorDepth obj)
		{
			if (ReferenceEquals(null, obj)) {
				return false;
			}
			if (ReferenceEquals(this, obj)) {
				return true;
			}
			return obj.colors == this.colors && obj.bpp == this.bpp;
		}

		public override bool Equals(object obj)
		{
			if (ReferenceEquals(null, obj)) {
				return false;
			}
			if (ReferenceEquals(this, obj)) {
				return true;
			}
			if (obj.GetType() != typeof(ColorDepth)) {
				return false;
			}
			return Equals((ColorDepth)obj);
		}

		public override int GetHashCode()
		{
			unchecked {
				return (this.colors.GetHashCode() * 397) ^ this.bpp;
			}
		}
	}
}